#include <iostream>
#include <string>
#include <cstring>
#include <cstdlib>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>

//没有按照指定的格式启动程序，提示正确格式
void Usage(std::string proc)
{
    std::cout << "Usage:\n\t" << proc << " serverip serverport\n"
              << std::endl;
}

int main(int argc, char *argv[])
{
    if(argc!=3)
    {
        Usage(argv[0]);
        exit(1);
    }
    std::string serverip=argv[1];// 获得IP
    uint16_t serverport=std::stoi(argv[2]);// 获得端口号


    //创建套接字
    int sockfd=socket(AF_INET,SOCK_DGRAM,0);
    if(sockfd<0)//创建失败
    {
        std::cerr<<"socket error"<<std::endl;
    }
    
    //地址结构体
    struct sockaddr_in server;
    memset(&server,0,sizeof(server));

    //填充地址结构体
    server.sin_family=AF_INET;

    //端口号，需要由主机序列转为网络序列
    server.sin_port=htons(serverport);

    //IP地址，需要从字符串转为 4字节
    server.sin_addr.s_addr=inet_addr(serverip.c_str());

    //客户端不需要调用bind函数，而是由操作系统自动绑定随机的端口号
    //如果不同的客户端都绑定同一个端口号，可能会导致端口号冲突

    std::string message;//消息
    while(true)
    {
        std::cout<<"Please Enter# ";
        std::getline(std::cin,message);//输入消息

        //发送数据报，传接收方的地址（要发给谁）
        sendto(sockfd,message.c_str(),message.size(),0,(struct sockaddr*)&server,sizeof(server));

        //一个客户端可以向多个服务器发消息，所以需要另外定义一个地址结构体
        //获取 作出应答的发送方的地址
        struct sockaddr_in peer;
        socklen_t len=sizeof(peer);
        char buffer[1024];

        //接收数据报
        ssize_t n=recvfrom(sockfd,buffer,sizeof(buffer),0,(struct sockaddr*)&peer,&len);

        //接收到了
        if(n>0)
        {
            buffer[n]=0;
            std::cout<<"server echo# "<<buffer<<std::endl;
        }

    }
    return 0;
}